﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using popLib;
using Microsoft.Reporting.WinForms;
using System.Collections;
using System.Drawing.Printing;
using System.Drawing.Imaging;
using popLib.ModelSystem;

namespace popLib.ExtensionClass
{
    public class RDLCReportViewer : Form
    {
        public string ReportFile { get; set; }
        public Hashtable DataSource { get; set; }
        public short NumberOfCopies { get; set; }
        public bool IsPrinted { get; set; }
        public bool IsReviewReport
        {
            get { return ReportViewerControl.ShowPrintButton; }
            set
            {
                ReportViewerControl.ShowPrintButton = value;
                ReportViewerControl.ShowExportButton = value;
            }
        }
        public ReportViewer ReportViewerControl { get; set; }
        public PaperSize PrinterPaperSize { get; set; }
        public Margins PrinterMargins { get; set; }
        public bool IsShowDialog { get; set; }

        public delegate void BeforePrintEvent();
        public event BeforePrintEvent BeforePrint;

        public virtual void InitReportBeforePrint()
        {
        }

        public RDLCReportViewer(string title, string reportFile)
        {            
            InitAll(reportFile);
            this.Text = title;
        }

        public RDLCReportViewer(string reportFile)
        {            
            InitAll(reportFile);
        }

        private void InitAll(string reportFile)
        {
            IsShowDialog = true;


            #region InitializeComponent
            ReportViewerControl = new ReportViewer();
            ReportViewerControl.Dock = DockStyle.Fill;
            ReportViewerControl.PrintingBegin += new Microsoft.Reporting.WinForms.ReportPrintEventHandler(this.reportViewer1_PrintingBegin);

            InitializeComponent();
            #endregion

            if (NumberOfCopies == 0 || NumberOfCopies == null)
                NumberOfCopies = 1;
            ReportFile = FileLib.getFullPath(reportFile);
            DataSource = new Hashtable();
        }

        private void ReportViewer_Load(object sender, EventArgs e)
        {
            LoadParametersAndDataSource();
            ReportViewerControl.RefreshReport();
        }

        private void LoadParametersAndDataSource()
        {
            if (!File.Exists(ReportFile))
            {
                Global.FormMessage(Global.FormMessageType.ReportNotFound, Path.GetFileNameWithoutExtension(ReportFile) );
                return;
            }

            ReportViewerControl.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Local;
            ReportViewerControl.LocalReport.ReportPath = ReportFile;

            //add parameters--------------------------------------------------
            PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (PropertyInfo property in properties)
            {

                //property.Name, property.GetValue(this, null)
                switch (property.GetType().Name.ToLower())
                {
                    case "datetime":
                        ReportViewerControl.LocalReport.SetParameters(new ReportParameter(property.Name, ((DateTime)property.GetValue(this, null)).ToShortDateString()));
                        break;
                    case "double": 
                    case "int":
                    case "int16":
                    case "int32":
                    case "string":
                    case "runtimepropertyinfo":
                        ReportViewerControl.LocalReport.SetParameters(new ReportParameter(property.Name, property.GetValue(this, null).GetString() ));
                        break;
                    default:
                        //FormLib.alert(property.Name + ":" + property.GetType().Name);
                        break;
                }
            }

            //add datasource--------------------------------------------------
            foreach (string key in DataSource.Keys)
            {
                ReportViewerControl.LocalReport.DataSources.Add(new ReportDataSource() { Name = key, Value = DataSource[key] });
            }
            try
            {
                var pagesetting = ReportViewerControl.GetPageSettings();
                pagesetting.Margins = PrinterMargins == null ? new Margins(30, 10, 30, 30) : PrinterMargins;
                pagesetting.PaperSize = PrinterPaperSize == null ? new System.Drawing.Printing.PaperSize("PaperA4", 827, 1169) : PrinterPaperSize;
                ReportViewerControl.SetPageSettings(pagesetting);
                ReportViewerControl.SetDisplayMode(DisplayMode.PrintLayout);
                ReportViewerControl.PrinterSettings.Copies = NumberOfCopies;
            }
            catch (Exception)
            {
                FormLib.alert("Xin vui lòng cài đặt máy in trước khi in báo cáo!!");
            }
        }

        private void reportViewer1_PrintingBegin(object sender, ReportPrintEventArgs e)
        {
            IsPrinted = true;
        }
                
        public void Print(bool showPrintPreview = false, bool showPrinterDialog = false)
        {
            if(BeforePrint != null)
                BeforePrint();

            InitReportBeforePrint();

            if (showPrintPreview)
            {
                if(IsShowDialog)
                    this.ShowDialog();
                else
                    this.Show();
            }
            else
            {
                DoPrint(showPrinterDialog);
            }
        }

        #region QuickReportFunctions
        
        private int m_currentPageIndex;
        private IList<Stream> m_streams;

        private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
        {
            Stream stream = new FileStream( FileLib.getRandomName(name ,null, fileNameExtension), FileMode.Create);
            m_streams.Add(stream);
            return stream;
        }

        private void Export(LocalReport report)
        {
            string deviceInfo =
              "<DeviceInfo>" +
              "  <OutputFormat>EMF</OutputFormat>" +
              "  <PageWidth>8.5in</PageWidth>" +
              "  <PageHeight>11.7in</PageHeight>" +
              "  <MarginTop>0.25in</MarginTop>" +
              "  <MarginLeft>0.25in</MarginLeft>" +
              "  <MarginRight>0.25in</MarginRight>" +
              "  <MarginBottom>0.25in</MarginBottom>" +
              "</DeviceInfo>";

            Warning[] warnings;
            m_streams = new List<Stream>();
            report.Render("Image", deviceInfo, CreateStream, out warnings);
            foreach (Stream stream in m_streams)
                stream.Position = 0;
        }

        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
            ev.Graphics.DrawImage(pageImage, ev.PageBounds);
            m_currentPageIndex++;
            ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
        }

        private  void DoPrint(bool showPrinterDialog)
        {
            LoadParametersAndDataSource();
            Export(ReportViewerControl.LocalReport);
            m_currentPageIndex = 0;
            
            if (m_streams == null || m_streams.Count == 0)
                return;

            PrintDocument printDoc = new PrintDocument();
            printDoc.PrinterSettings.DefaultPageSettings.Margins = PrinterMargins == null ? new Margins(30, 10, 30, 30) : PrinterMargins;
            printDoc.PrinterSettings.DefaultPageSettings.PaperSize = PrinterPaperSize == null ? new System.Drawing.Printing.PaperSize("PaperA4", 827, 1169) : PrinterPaperSize;
            printDoc.PrinterSettings.Copies = NumberOfCopies;
            printDoc.EndPrint += new PrintEventHandler(printDoc_EndPrint);

            if (showPrinterDialog)
            {
                PrintDialog a = new PrintDialog();
                a.PrinterSettings = printDoc.PrinterSettings;
                if (a.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                    return;
                printDoc.PrinterSettings = a.PrinterSettings;
            }



            if (!printDoc.PrinterSettings.IsValid)
            {
                string msg = String.Format(
                   "Can't find printer \"{0}\".", printDoc.PrinterSettings.PrinterName);
                MessageBox.Show(msg, "Print Error");
                return;
            }

            printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
            try
            {
                printDoc.Print();
            }
            catch (Exception ex) { FormLib.alert(ex.Message + "\r\nPlease check your printer's connection and make sure available printer is marked as default printer.", "Error Printing"); }
        }

        void printDoc_EndPrint(object sender, PrintEventArgs e)
        {
            IsPrinted = true;
        }
        #endregion

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // RDLCReportViewer
            // 
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.KeyPreview = true;
            this.Name = "RDLCReportViewer";
            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.RDLCReportViewer_KeyUp);
            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.Controls.Add(ReportViewerControl);
            this.MinimizeBox = false;
            this.Load += new System.EventHandler(this.ReportViewer_Load);
            this.Size = new Size(800, 600);
            this.ResumeLayout(false);

        }

        private void RDLCReportViewer_KeyUp(object sender, KeyEventArgs e)
        {
            if (IsReviewReport && (e.KeyCode == Keys.F7 || (e.Control && e.KeyCode == Keys.P)))
                ReportViewerControl.PrintDialog();
        }
    }
}
